package com.farent.solutions.jeeunit;



/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
import com.farent.solutions.common.discovery.ejbs.EJBFieldVisitor;
import com.farent.solutions.common.discovery.ejbs.EjbAnnotationProvider;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.dbunit.ext.mysql.MySqlDataTypeFactory;
import org.dbunit.operation.DatabaseOperation;
import org.dbunit.database.IDatabaseConnection;
import org.hibernate.internal.SessionImpl;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.rules.ExternalResource;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

/**
 *
 * @author Farouk.Alhassan
 */
public class AbstractDAOTest {
   
    @Rule
    public BeforeAfterMethodRule testDb = new BeforeAfterMethodRule();
    @ClassRule
    public static BeforeAfterClassRule beforeRuleAfterClass = new BeforeAfterClassRule();
    protected static EntityManagerFactory entityManagerFactory;
    protected static EntityManager entityManager;
    protected static IDatabaseConnection connection;
    protected static IDataSet dataset;

    public class BeforeAfterMethodRule implements TestRule {

        private final BeforeAfterRule initializer = new BeforeAfterRule();

        @Override
        public Statement apply(Statement stmnt, Description d) {
            return initializer.apply(stmnt, d);
        }

        private class BeforeAfterRule extends ExternalResource {

            @Override
            protected void after() {
                entityManager.getTransaction().rollback();
                super.after();
            }

            @Override
            protected void before() throws Throwable {
                EJBFieldVisitor instance = new EJBFieldVisitor();
                PersistenceContextProvider contextProvider = new PersistenceContextProvider();
                instance.getProviders().put(PersistenceContext.class, contextProvider);
                instance.scanAndInitializeEjbs();
                instance.visit(AbstractDAOTest.this);
                DatabaseOperation.CLEAN_INSERT.execute(
                        connection, dataset);
                entityManager.getTransaction().begin();
            }
        }
    }

    public static class BeforeAfterClassRule implements TestRule {

        final BeforeRuleAfterClass instance = new BeforeRuleAfterClass();

        @Override
        public Statement apply(Statement stmnt, Description d) {
            return instance.apply(stmnt, d);
        }

        private class BeforeRuleAfterClass extends ExternalResource {

            @Override
            protected void after() {
                entityManager.close();
                entityManagerFactory.close();
            }

            @Override
            protected void before() throws Throwable {

                entityManagerFactory = Persistence.createEntityManagerFactory("JeeunitPU");
                entityManager =
                        entityManagerFactory.createEntityManager();

                connection = new DatabaseConnection(((SessionImpl) (entityManager.getDelegate())).connection());
                connection.getConfig().setProperty(
                        DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory());

                FlatXmlDataSetBuilder flatXmlDataSetBuilder =
                        new FlatXmlDataSetBuilder();
                flatXmlDataSetBuilder.setColumnSensing(true);

                dataset = flatXmlDataSetBuilder.build(
                        Thread.currentThread().getContextClassLoader().getResourceAsStream("test-dataset.xml"));

            }
        }
    }
    
    public void commitAndRestartTransaction()
    {
        entityManager.getTransaction().commit();
        entityManager.getTransaction().begin();
    }
    
    public class PersistenceContextProvider implements EjbAnnotationProvider<PersistenceContext>
    {
        @Override
        public EntityManager provide() {
            return entityManager;
        }
    }
}
